import { Component, find } from 'cc'
import { ZBaseBinder } from './ZBaseBinder'

/**
 * 属性绑定选项接口
 * 定义了绑定节点或组件到属性时的各种选项
 */
export interface PropertyBindingOptions {
	/** 是否静默处理错误（默认为 false） */
	silent?: boolean
	/** 是否为可选绑定（不存在时不报错） */
	optional?: boolean
	/** 要绑定的组件类型（如果指定，将绑定组件而不是节点） */
	component?: new (...args: any[]) => Component
	/** 如果组件不存在，是否创建 */
	createComponent?: boolean
	/** 自定义错误处理函数 */
	onError?: (error: string) => void
}

/**
 * 批量绑定配置类型
 * 支持简单字符串路径或带选项的对象
 */
export type PropertyBindingConfig =
	| string
	| {
			path: string
			component?: new (...args: any[]) => Component
			silent?: boolean
			optional?: boolean
			createComponent?: boolean
			onError?: (error: string) => void
	  }

/**
 * 属性绑定器
 *
 * 负责将节点或组件绑定到组件属性，支持单个绑定和批量绑定。
 * 可以绑定节点或指定类型的组件，并提供丰富的选项控制绑定行为。
 *
 * @example
 * // 创建绑定器
 * const binder = new ZPropertyBinder(this);
 *
 * // 绑定节点
 * binder.bind('UI/Container', 'container');
 *
 * // 绑定组件
 * binder.bind('UI/Label', 'titleLabel', { component: Label });
 *
 * // 批量绑定
 * binder.bindBatch({
 *   container: 'UI/Container',
 *   titleLabel: { path: 'UI/Label', component: Label }
 * });
 */
export class ZPropertyBinder extends ZBaseBinder {
	/**
	 * 创建属性绑定器
	 * @param component 要绑定属性的组件实例
	 */
	constructor(component: Component) {
		super(component)
	}

	/**
	 * 绑定节点或组件到属性
	 * @param path 节点路径，相对于组件所在节点
	 * @param property 要绑定的属性名
	 * @param options 绑定选项
	 * @returns this 实例，支持链式调用
	 */
	public bind(path: string, property: string, options: PropertyBindingOptions = {}): this {
		const { silent = false, optional = false, component = null, createComponent = true, onError } = options

		// 检查属性是否存在
		if (!this.component.hasOwnProperty(property)) {
			this.handleError(`Property "${property}" not found in ${this.component.constructor.name}`, silent, onError)
			return this
		}

		// 查找节点
		const node = find(path, this.component.node)
		if (!node) {
			if (!optional) {
				this.handleError(
					`Node not found at path: "${path}" in ${this.component.constructor.name}`,
					silent,
					onError
				)
			}
			return this
		}

		// 如果指定了组件类型，绑定组件
		if (component) {
			let targetComponent = node.getComponent(component)

			// 如果组件不存在且需要创建
			if (!targetComponent && createComponent) {
				targetComponent = node.addComponent(component)
			}

			// 如果组件不存在且不创建
			if (!targetComponent) {
				this.handleError(`Component "${component.name}" not found on node at path: "${path}"`, silent, onError)
				return this
			}

			// 绑定组件到属性
			this.component[property] = targetComponent
		} else {
			// 绑定节点到属性
			this.component[property] = node
		}

		return this
	}

	/**
	 * 批量绑定节点或组件到属性
	 * @param bindings 绑定配置对象 { 属性名: 配置 }
	 * @returns this 实例，支持链式调用
	 */
	public bindBatch(bindings: Record<string, PropertyBindingConfig>): this {
		const keys = Object.keys(bindings)
		for (let i = 0; i < keys.length; i++) {
			const property = keys[i]
			const config = bindings[property]

			if (typeof config === 'string') {
				// 简单字符串路径，绑定节点
				this.bind(config, property)
			} else {
				// 带选项的对象
				const path = config.path
				const options = {
					component: config.component,
					silent: config.silent,
					optional: config.optional,
					createComponent: config.createComponent,
					onError: config.onError
				}
				this.bind(path, property, options)
			}
		}
		return this
	}

	/**
	 * 处理错误
	 * @param message 错误消息
	 * @param silent 是否静默处理
	 * @param onError 自定义错误处理函数
	 * @private
	 */
	private handleError(message: string, silent: boolean, onError?: (error: string) => void): void {
		if (onError) {
			// 使用自定义错误处理
			onError(message)
		} else if (!silent) {
			// 默认错误处理
			console.error(`[ZPropertyBinder] ${message}`)
		}
	}
}
